package com.pangu.core.engine.game;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.SocketIOClient;
import com.pangu.core.BMDataContext;
import com.pangu.core.cache.CacheHelper;
import com.pangu.core.engine.game.iface.Record;
import com.pangu.core.engine.game.model.PlayerRecordDezhou;
import com.pangu.core.engine.game.model.PlayerRecordNiuniu;
import com.pangu.core.engine.game.state.GameEvent;
import com.pangu.core.nettyserver.client.NettyClients;
import com.pangu.core.nettyserver.handler.BeiMiClient;
import com.pangu.util.GameUtils;
import com.pangu.util.UKTools;
import com.pangu.util.disruptor.DisruptorHandler;
import com.pangu.util.rules.model.BetStatus;
import com.pangu.util.rules.model.Board;
import com.pangu.util.rules.model.GameHistoryBoard;
import com.pangu.util.rules.model.JoinRoom;
import com.pangu.util.rules.model.Playeready;
import com.pangu.web.model.GamePlayway;
import com.pangu.web.model.GameRoom;
import com.pangu.web.model.PlayUserClient;
import com.pangu.web.model.Token;
import com.pangu.web.service.repository.es.PlayUserClientESRepository;
import com.pangu.web.service.repository.jpa.GameRoomRepository;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: NiuniuEngine
 * @Description: 牛牛引擎
 * @author 老王
 * @date 2018年5月17日 下午7:46:30
 *
 */
@Slf4j
@Service(value = "niuniuEngine")
public class NiuniuEngine {

	public JSONObject getHistoryBoards(String roomid, JSONObject json) {
		Object object = CacheHelper.getGameHistoryBoardCache().getCacheObject(roomid, BMDataContext.SYSTEM_ORGI);
		if (object != null) {
			List<GameHistoryBoard> list = (List<GameHistoryBoard>) object;
			for (GameHistoryBoard gameHistoryBoard : list) {
				gameHistoryBoard.setCreateTime(null);
				gameHistoryBoard.setId(null);
				gameHistoryBoard.setRoomId(null);
			}
			json.put("historyBoards", list);
		}
		return json;
	}

	/**
	 * 得到下注金额最大的玩家
	 * @param playUsers
	 * @returnd
	 */
	public int getBiggerSeat(List<PlayUserClient> playUsers) {
		Map<String, Double> tm = new HashMap<>();
		// 先分组
		for (PlayUserClient playUserClient2 : playUsers) {
			List<PlayerRecordNiuniu> record = (List<PlayerRecordNiuniu>) CacheHelper.getGameRecordNiuNiuCacheBean()
					.getCacheObject(playUserClient2.getId(), playUserClient2.getOrgi());
			if (null == record) {
				continue;
			}
			for (PlayerRecordNiuniu playerRecordNiuniu : record) {
				if (tm.containsKey(playerRecordNiuniu.getGameSubType())) {
					tm.put(playerRecordNiuniu.getGameSubType(),
							playerRecordNiuniu.getCoin() + tm.get(playerRecordNiuniu.getGameSubType()));
				} else {
					tm.put(playerRecordNiuniu.getGameSubType(), playerRecordNiuniu.getCoin());
				}
			}
		}
		Double bigger = 0d;
		String seat = null;
		for (String key : tm.keySet()) {
			if (tm.get(key) > bigger) {
				bigger = tm.get(key);
				seat = key;
			}
		}

		return seat != null ? Integer.parseInt(seat) : 0;

	}

	/*
	 * AI下注，实时同步数据到前台
	 */
	public void betGameRequest(GameRoom gameRoom, PlayUserClient userClient, int seat, double coin) {

		if (!BMDataContext.GameStatusEnum.BET.toString().equals(gameRoom.getStatus())) {
			log.info("过了下注时间····················");
			return;
		}
		// 读取该局下注记录，跟新下注记录，无法取消哦。
		List<PlayerRecordNiuniu> record = (List<PlayerRecordNiuniu>) CacheHelper.getGameRecordNiuNiuCacheBean()
				.getCacheObject(userClient.getId(), userClient.getOrgi());

		double rest = getTotalCoin(record);// 检查历史下注不能大于大的金额
		// 先校验下注金额是否大于该用户所只有金额
		if (coin + rest > userClient.getGoldcoins()) {
			log.info("下注失败····金额太大了·····");
			return;
		}

		if (record == null) {
			record = new ArrayList<>();
		}
		PlayerRecordNiuniu pr = new PlayerRecordNiuniu();
		pr.setOrgi(userClient.getOrgi());
		pr.setPlayerId(userClient.getId());
		pr.setGameSubType(seat + "");
		pr.setCoin(coin);
		pr.setGameType(gameRoom.getPlayway());
		pr.setGameTime(new Date());
		pr.setSummaryId(UKTools.getUUID());
		pr.setPlayerType(2 + "");
		record.add(pr);
		ActionTaskUtils.sendEvent(pr.getCommand(), pr, gameRoom);
		CacheHelper.getGameRecordNiuNiuCacheBean().put(userClient.getId(), record, userClient.getOrgi());
		log.info("userClient.getId():{},下注金额{}", userClient.getId(), coin);
	}


		/**
			 * @Description :下注，实时同步数据到前台
			 *              <p>
			 *             所有的下注记录都是保存在缓存里面，只有在结算的时候才会持久化到数据库里面
			 *              <p>
			 *             
			 */
	public void betGameRequest(SocketIOClient client, Token userToken, int seat, double coin) {

		BetStatus bs = new BetStatus();
		// 缓存里面获取到玩家客户端，该客户端用户登陆的时候会创建
		PlayUserClient userClient = (PlayUserClient) CacheHelper.getApiUserCacheBean()
				.getCacheObject(userToken.getUserid(), userToken.getOrgi());

		String roomid = (String) CacheHelper.getRoomMappingCacheBean().getCacheObject(userClient.getId(),
				userClient.getOrgi());
		if (StringUtils.isBlank(roomid)) {
			return;
		}
		GameRoom gameRoom = (GameRoom) CacheHelper.getGameRoomCacheBean().getCacheObject(roomid, userClient.getOrgi());

		if (!BMDataContext.GameStatusEnum.BET.toString().equals(gameRoom.getStatus())) {
			bs.setMessage("已经过了下注时间,无法下注！");
			bs.setBetstatus(-1);
			client.sendEvent(bs.getCommand(), bs);
			return;
		}
		List<PlayerRecordNiuniu> record = (List<PlayerRecordNiuniu>) CacheHelper.getGameRecordNiuNiuCacheBean()
				.getCacheObject(userClient.getId(), userToken.getOrgi());
		double rest = getTotalCoin(record);// 检查历史下注不能大于大的金额
		// 先校验下注金额是否大于该用户所只有金额
		if (coin + rest > userClient.getGoldcoins()) {
			log.info("下注额大于所拥有的金币数量");
			bs.setMessage("下注额大于所拥有的金币数量");
			bs.setBetstatus(0);
			client.sendEvent(bs.getCommand(), bs);
			return;
		}

		// 读取该局下注记录，跟新下注记录，无法取消哦。
		if (record == null) {
			record = new ArrayList<>();
		}
		PlayerRecordNiuniu pr = new PlayerRecordNiuniu();
		pr.setOrgi(userToken.getOrgi());
		pr.setPlayerId(userClient.getId());
		pr.setGameSubType(seat + "");
		pr.setCoin(coin);
		pr.setGameType(gameRoom.getPlayway());
		pr.setGameTime(new Date());
		pr.setSummaryId(UKTools.getUUID());
		pr.setPlayerType(1 + "");

		record.add(pr);
		// this.betSendRequest(gameRoom, pr);// 广播消息
		ActionTaskUtils.sendEvent(pr.getCommand(), pr, gameRoom);
		CacheHelper.getGameRecordNiuNiuCacheBean().put(userClient.getId(), record, userToken.getOrgi());
		// 反馈消息
		bs.setMessage("操作成功");
		bs.setBetstatus(1);
		client.sendEvent(bs.getCommand(), bs);

	}

	public double getTotalCoin(List<PlayerRecordNiuniu> record) {
		double result = 0;
		if (record == null) {
			return 0;
		}
		for (PlayerRecordNiuniu playerRecordNiuniu : record) {
			result = result + playerRecordNiuniu.getCoin();
		}
		return result;

	}

	/*
	 * 广播下注数据 ,ai
	 * 
	 * public void betSendRequest(GameRoom gameRoom, Record record) {
	 * record.setCommand(BMDataContext.BEIMI_BETRECORD_EVENT);
	 * 
	 * }
	 */

	/**
	 * 开始游戏
	 * 
	 * @param roomid
	 * 
	 * @param orgi
	 * @return
	 */
	public void startGameRequest(String roomid, PlayUserClient playUser, String orgi) {
		GameRoom gameRoom = (GameRoom) CacheHelper.getGameRoomCacheBean().getCacheObject(roomid, orgi);
		if (gameRoom != null) {
			playUser.setRoomready(true);
			// 这个时候才把缓存存到 GamePlayerCache
			CacheHelper.getGamePlayerCacheBean().put(playUser.getId(), playUser, playUser.getOrgi());
			ActionTaskUtils.roomReady(gameRoom, GameUtils.getGame(gameRoom.getPlayway(), gameRoom.getOrgi()));
			DisruptorHandler.published(playUser, BMDataContext.getContext().getBean(PlayUserClientESRepository.class));
			ActionTaskUtils.sendEvent(playUser.getId(), new Playeready(playUser.getId(), "playeready"));
		}
	}

	public void gameRequest(String userid, String playway, String room, String orgi, PlayUserClient userClient,
			BeiMiClient beiMiClient) {
		GameEvent gameEvent = gameRequest(userClient.getId(), beiMiClient.getPlayway(), beiMiClient,
				beiMiClient.getOrgi(), userClient);
		if (gameEvent == null) {
			return;
		}
		/**
		 * 表示游戏可以开始了
		 */
		if (userClient != null) {
			userClient.setGamestatus(BMDataContext.GameStatusEnum.READY.toString());
		}

		/**
		 * 游戏状态 ， 玩家请求 游戏房间，活动房间状态后，发送事件给 StateMachine，由 StateMachine驱动 游戏状态 ，
		 * 此处只负责通知房间内的玩家 1、有新的玩家加入
		 * 2、给当前新加入的玩家发送房间中所有玩家信息（不包含隐私信息，根据业务需求，修改PlayUserClient的字段，剔除掉隐私信息后发送）
		 */
		ActionTaskUtils.sendEvent("joinroom", new JoinRoom(userClient, gameEvent.getIndex(),
				gameEvent.getGameRoom().getPlayers(), gameEvent.getGameRoom()), gameEvent.getGameRoom());
		/**
		 * 发送给单一玩家的消息
		 */
		ActionTaskUtils.sendPlayers(beiMiClient, gameEvent.getGameRoom());

		/**
		 * 当前是在游戏中还是 未开始
		 */
		Board board = (Board) CacheHelper.getBoardCacheBean().getCacheObject(gameEvent.getRoomid(),
				gameEvent.getOrgi());
		if (board == null) {
			// 通知状态
			GameUtils.getGame(beiMiClient.getPlayway(), gameEvent.getOrgi()).change(gameEvent); // 通知状态机 , 此处应由状态机处理异步执行
			return;
		}
	}

	/*
	 * 初始化百人牛牛的方法
	 */
	public void CreateGame(String playway, String orgi) {
		GameEvent gameEvent = null;
		// 获取玩法
		GamePlayway gamePlayway = (GamePlayway) CacheHelper.getSystemCacheBean().getCacheObject(playway, orgi);
		if (gamePlayway == null) {
			log.error("找不到该玩法······················");
			return;
		}

		PlayUserClient playerUser = CacheHelper.getQuenePlayerCache().poll(orgi, BMDataContext.GAME_NIUNIU_AI_COIN);
		if (playerUser == null) {
			log.error("没有符合要求创牛牛的人·············");
			return;
		}

		GameRoom gameRoom = (GameRoom) CacheHelper.getQueneCache().get(playway, orgi);
		if (null == gameRoom) {
			gameRoom = this.creatGameRoom(gamePlayway, playerUser.getId());
		}

		playerUser.setPlayerindex(System.currentTimeMillis());
		playerUser.setBlank(true);
		CacheHelper.getGamePlayerCacheBean().put(playerUser.getId(), playerUser, orgi);
		// 生成一个事件
		gameEvent = new GameEvent(gamePlayway.getPlayers(), gamePlayway.getCardsnum(), orgi);

		if (gameRoom == null) {
			gameRoom = this.creatGameRoom(gamePlayway, playerUser.getId());
		}
		/**
		 * 设置游戏当前已经进行的局数
		 */
		gameRoom.setCurrentnum(0);
		/**
		 * 更新缓存
		 */
		CacheHelper.getGameRoomCacheBean().put(gameRoom.getId(), gameRoom, orgi);
		gameEvent.setGameRoom(gameRoom);
		gameEvent.setRoomid(gameRoom.getId());
		this.joinRoom(gameRoom, playerUser, new ArrayList<PlayUserClient>());// 加入房间

		gameEvent.setEvent(BeiMiGameEvent.ENTER.toString());
		CacheHelper.getQueneCache().put(gameRoom, orgi);
		// 启动AI 加入设置好的AI
		GameUtils.getGame(playway, orgi).change(gameEvent);
	}

	/**
	 * 玩家房间选择， 新请求，游戏撮合， 如果当前玩家是断线重连， 或者是 退出后进入的，则第一步检查是否已在房间 如果已在房间，直接返回
	 * 
	 * @param userid
	 * @param orgi
	 * @return
	 */
	private GameEvent gameRequest(String userid, String playway, BeiMiClient beiMiClient, String orgi,
			PlayUserClient playUser) {
		GameEvent gameEvent = null;
		// 第一次进来 roomId 为空。
		String roomid = (String) CacheHelper.getRoomMappingCacheBean().getCacheObject(userid, orgi);
		// 获取玩法
		GamePlayway gamePlayway = (GamePlayway) CacheHelper.getSystemCacheBean().getCacheObject(playway, orgi);
		if (gamePlayway == null) {
			return null;
		}

		boolean needtakequene = false;
		// 生成一个事件
		gameEvent = new GameEvent(gamePlayway.getPlayers(), gamePlayway.getCardsnum(), orgi);

		GameRoom gameRoom = null;
		if (!StringUtils.isBlank(roomid) && CacheHelper.getGameRoomCacheBean().getCacheObject(roomid, orgi) != null) {//
			gameRoom = (GameRoom) CacheHelper.getGameRoomCacheBean().getCacheObject(roomid, orgi);
			// 直接加入到 系统缓存 （只有一个地方对GameRoom进行二次写入，避免分布式锁）
		} else {
			gameRoom = (GameRoom) CacheHelper.getQueneCache().poll(playway, orgi);
			if (gameRoom != null) {
				/**
				 * 修正获取gameroom获取的问题，因为删除房间的时候，为了不损失性能，没有将 队列里的房间信息删除，如果有玩家获取到这个垃圾信息
				 * 则立即进行重新获取房价，
				 */
				while (CacheHelper.getGameRoomCacheBean().getCacheObject(gameRoom.getId(),
						gameRoom.getOrgi()) == null) {
					gameRoom = (GameRoom) CacheHelper.getQueneCache().poll(playway, orgi);
					if (gameRoom == null) {
						break;
					}
				}
			}
			if (gameRoom == null) { // 无房间 ， 需要
				gameRoom = this.creatGameRoom(gamePlayway, userid, false, beiMiClient);
			} else {
				playUser.setPlayerindex(System.currentTimeMillis());// 从后往前坐，房主进入以后优先坐在 首位
				needtakequene = true;
			}

			if (gameRoom != null) {

				/**
				 * 设置游戏当前已经进行的局数
				 */
				gameRoom.setCurrentnum(0);
				/**
				 * 更新缓存
				 */
				CacheHelper.getGameRoomCacheBean().put(gameRoom.getId(), gameRoom, orgi);

				/**
				 * 如果当前房间到达了最大玩家数量，则不再加入到 撮合队列
				 */
				List<PlayUserClient> playerList = CacheHelper.getGamePlayerCacheBean().getCacheObject(gameRoom.getId(),
						gameRoom.getOrgi());
				if (playerList.size() == 0) {
					gameEvent.setEvent(BeiMiGameEvent.ENTER.toString());
				} else {
					gameEvent.setEvent(BeiMiGameEvent.JOIN.toString());
				}
				gameEvent.setGameRoom(gameRoom);
				gameEvent.setRoomid(gameRoom.getId());

				/**
				 * 无条件加入房间
				 */
				this.joinRoom(gameRoom, playUser, playerList);

				for (PlayUserClient temp : playerList) {
					if (temp.getId().equals(playUser.getId())) {
						gameEvent.setIndex(playerList.indexOf(temp));
						break;
					}
				}

				/**
				 * 如果当前房间到达了最大玩家数量，则不再加入到 撮合队列
				 */
				if (playerList.size() < gamePlayway.getPlayers() && needtakequene == true) {
					CacheHelper.getQueneCache().put(gameRoom, orgi); // 未达到最大玩家数量，加入到游戏撮合 队列，继续撮合
				}

			}

		}

		return gameEvent;
	}

	/**
	 * 创建一个空房间，
	 * 
	 * @param playway
	 * @param userid
	 * @return
	 */
	private GameRoom creatGameRoom(GamePlayway playway, String userid) {
		GameRoom gameRoom = new GameRoom();
		gameRoom.setCreatetime(new Date());
		gameRoom.setRoomid(UKTools.getUUID());
		gameRoom.setUpdatetime(new Date());

		if (playway != null) {
			gameRoom.setPlayway(playway.getId());
			gameRoom.setRoomtype(playway.getRoomtype());
			gameRoom.setPlayers(playway.getPlayers());
		}
		gameRoom.setPlayers(playway.getPlayers());
		gameRoom.setCardsnum(playway.getCardsnum());

		gameRoom.setCurpalyers(1);
		gameRoom.setCardroom(false);

		gameRoom.setStatus(BeiMiGameEnum.CRERATED.toString());
		gameRoom.setStatusTime(System.currentTimeMillis());

		gameRoom.setCardsnum(playway.getCardsnum());

		gameRoom.setCurrentnum(0);

		gameRoom.setCreater(userid);

		gameRoom.setMaster(userid);
		gameRoom.setNumofgames(playway.getNumofgames()); // 无限制
		gameRoom.setOrgi(playway.getOrgi());

		gameRoom.setRoomtype(BMDataContext.ModelType.HALL.toString());// 大厅模式

		CacheHelper.getQueneCache().put(gameRoom, playway.getOrgi()); // 未达到最大玩家数量，加入到游戏撮合 队列，继续撮合

		DisruptorHandler.published(gameRoom, null, BMDataContext.getContext().getBean(GameRoomRepository.class),
				BMDataContext.UserDataEventType.SAVE.toString());

		return gameRoom;
	}

	/**
	 * 创建新房间 ，需要传入房间的玩法 ， 玩法定义在 系统运营后台，玩法创建后，放入系统缓存 ， 客户端进入房间的时候，传入 玩法ID参数
	 * 
	 * @param playway
	 * @param userid
	 * @return
	 */
	private GameRoom creatGameRoom(GamePlayway playway, String userid, boolean cardroom, BeiMiClient beiMiClient) {
		GameRoom gameRoom = new GameRoom();
		gameRoom.setCreatetime(new Date());
		gameRoom.setRoomid(UKTools.getUUID());
		gameRoom.setUpdatetime(new Date());

		if (playway != null) {
			gameRoom.setPlayway(playway.getId());
			gameRoom.setRoomtype(playway.getRoomtype());
			gameRoom.setPlayers(playway.getPlayers());
		}
		gameRoom.setPlayers(playway.getPlayers());
		gameRoom.setCardsnum(playway.getCardsnum());

		gameRoom.setCurpalyers(1);
		gameRoom.setCardroom(cardroom);

		gameRoom.setStatus(BeiMiGameEnum.CRERATED.toString());

		gameRoom.setCardsnum(playway.getCardsnum());

		gameRoom.setCurrentnum(0);

		gameRoom.setCreater(userid);

		gameRoom.setMaster(userid);
		gameRoom.setNumofgames(playway.getNumofgames()); // 无限制
		gameRoom.setOrgi(playway.getOrgi());

		gameRoom.setRoomtype(BMDataContext.ModelType.HALL.toString());// 大厅模式

		CacheHelper.getQueneCache().put(gameRoom, playway.getOrgi()); // 未达到最大玩家数量，加入到游戏撮合 队列，继续撮合

		DisruptorHandler.published(gameRoom, null, BMDataContext.getContext().getBean(GameRoomRepository.class),
				BMDataContext.UserDataEventType.SAVE.toString());

		return gameRoom;
	}

	/**
	 * 
	 * 玩家加入房间
	 * 
	 * @param gameRoom
	 * @param playUser
	 * @param playerList
	 */
	public void joinRoom(GameRoom gameRoom, PlayUserClient playUser, List<PlayUserClient> playerList) {
		boolean inroom = false;
		for (PlayUserClient user : playerList) {
			if (user.getId().equals(playUser.getId())) {
				inroom = true;
				break;
			}
		}
		if (inroom == false) {
			playUser.setPlayerindex(System.currentTimeMillis());
			playUser.setGamestatus(BMDataContext.GameStatusEnum.READY.toString());
			playUser.setPlayertype(playUser.getPlayertype() == null ? BMDataContext.PlayerTypeEnum.NORMAL.toString()
					: playUser.getPlayertype());
			playUser.setRoomid(gameRoom.getId());
			playUser.setRoomready(false);

			playerList.add(playUser);
			NettyClients.getInstance().joinRoom(playUser.getId(), gameRoom.getId());
			CacheHelper.getGamePlayerCacheBean().put(playUser.getId(), playUser, playUser.getOrgi()); // 将用户加入到 room ，
																										// MultiCache
		}

		/**
		 * 不管状态如何，玩家一定会加入到这个房间
		 */
		CacheHelper.getRoomMappingCacheBean().put(playUser.getId(), gameRoom.getId(), playUser.getOrgi());
	}

}
